package com.shenma2009.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shenma2009.domain.ResultResponse;
import com.shenma2009.mapper.TbProductMapper;
import com.shenma2009.mapper.TbWareMapper;
import com.shenma2009.pojo.TbProduct;
import com.shenma2009.pojo.TbSecKill;
import com.shenma2009.pojo.TbWare;
import com.shenma2009.service.TbSecKillService;
import com.shenma2009.mapper.TbSecKillMapper;
import com.shenma2009.vo.IdVo;
import com.shenma2009.vo.KillVo;
import com.shenma2009.vo.PageVo;
import com.shenma2009.vo.TbSecKillVo;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
* @author 33509
* @description 针对表【tb_sec_kill(秒杀活动表)】的数据库操作Service实现
* @createDate 2023-05-04 15:05:26
*/
@Service
public class TbSecKillServiceImpl extends ServiceImpl<TbSecKillMapper, TbSecKill>
    implements TbSecKillService{

    @Autowired
    RedissonClient redissonClient;

    @Autowired
    TbProductMapper tbProductMapper;

    @Autowired
    TbWareMapper tbWareMapper;

    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Transactional
    public ResultResponse addKill(TbSecKillVo tbSecKillVo) {
        //-- 检查参数
        TbProduct tbProduct = tbProductMapper.selectById(tbSecKillVo.getProducId());
        if(tbProduct == null) {
            return ResultResponse.FAILED(404, "商品不存在");
        }

        //-- 扣减库存
        TbWare tbWare = tbWareMapper.selectOne(
                new QueryWrapper<TbWare>().lambda()
                        .eq(TbWare::getProductId, tbProduct.getProductId())
                        .last("limit 1")
        );
        if(tbWare == null || tbWare.getWareCount() < tbSecKillVo.getKillCount()) {
            return ResultResponse.FAILED(404, "产品库存不足");
        }

        tbWare.setWareCount(tbWare.getWareCount()-tbSecKillVo.getKillCount());
        tbWare.setUpdateTime(null);
        tbWareMapper.updateById(tbWare);

        //-- 增加秒杀活动
        TbSecKill tbSecKill = new TbSecKill();
        BeanUtils.copyProperties(tbSecKillVo, tbSecKill);

        save(tbSecKill);


        return ResultResponse.SUCCESS();
    }

    @Override
    public ResultResponse add(TbSecKillVo tbSecKillVo) {
        RLock rLock = redissonClient.getLock("kill_ware_lock");

        try {
            rLock.lock();
            return addKill(tbSecKillVo);
        } finally {
            rLock.unlock();
        }
    }

    @Override
    public ResultResponse listByPage(PageVo pageVo) {

        Page<TbSecKill> page = new Page<>(pageVo.getPageNum(), pageVo.getPageSize());

        Page<TbSecKill> tbSecKillPage = this.page(page, null);


        List<TbSecKillVo> collect = tbSecKillPage.getRecords().stream().map(item -> {
            TbSecKillVo tbSecKillVo = new TbSecKillVo();
            BeanUtils.copyProperties(item, tbSecKillVo);
            return tbSecKillVo;
        }).collect(Collectors.toList());

        Page<TbSecKillVo> voPage = new Page<>(pageVo.getPageNum(), pageVo.getPageSize());
        BeanUtils.copyProperties(tbSecKillPage, voPage);
        voPage.setRecords(collect);

        return ResultResponse.SUCCESS(voPage);
    }

    @Override
    public ResultResponse startKill(IdVo idVo) {
        //-- 检查活动是否存在
        TbSecKill tbSecKill = getById(idVo.getId());
        if(tbSecKill == null || !tbSecKill.getKillState().equals(0)) {
            return ResultResponse.FAILED(404, "活动不存在");
        }

        //-- 设置开始时间和结束时间
        Date beginDate = new Date();
        tbSecKill.setBeginTime(beginDate);

        // 默认是30分钟
        Date endDate = new Date(beginDate.getTime());
        endDate.setTime(beginDate.getTime() + 1000*60*30);
        tbSecKill.setEndTime(endDate);

        // 设置秒杀活动的状态
        tbSecKill.setKillState(1);
        tbSecKill.setUpdateTime(null);
        updateById(tbSecKill);

        //-- 开始抢购活动
        String key = "KILL_" + tbSecKill.getKillId();
        redisTemplate.opsForValue().set(key, tbSecKill.getKillCount());

        //-- 发送消息到死信队列，来回归库存
        // TODO


        return ResultResponse.SUCCESS();
    }

    @Override
    public ResultResponse doKill(KillVo killVo) {
        //-- 检查活动是否存在
        String key = "KILL_" + killVo.getKillId();
        Boolean hasKey = redisTemplate.hasKey(key);
        if(!hasKey) {
            return ResultResponse.FAILED(404, "活动不存在");
        }

        //-- 把请求放到MQ的队列中
        String message = JSON.toJSONString(killVo);
        rabbitTemplate.convertAndSend("secKillQueue", message);


        return ResultResponse.SUCCESS();
    }

    @Override
    public ResultResponse getKill(KillVo killVo) {

        //--
        String bigKey = "SEC_KILL_RESULT_" + killVo.getKillId();

        Object o = redisTemplate.opsForHash().get(bigKey, "" + killVo.getUserId());
        if(o == null) {
            return ResultResponse.FAILED(404, "请稍后再试");
        }

        //--
        Integer ret = (Integer) o;
        if(ret.equals(0)) {
            return ResultResponse.FAILED(202, "正在处理，请稍后");
        }
        else if(ret.equals(1)) {
            return ResultResponse.FAILED(200, "恭喜您，抢购成功，请及时支付");
        }
        else {
            return ResultResponse.FAILED(203, "非常抱歉，您没有抢购成功");
        }
    }

    //
    // TODO: 下面函数需要使用分布式锁和事务

    @Override
    public Boolean stopSecKIll(Integer killId) {
        //-- 判断活动是否存在（redis）
        String key = "KILL_" + killId;
        Boolean hasKey = redisTemplate.hasKey(key);
        if(!hasKey) {
            return false;
        }

        TbSecKill tbSecKill = null;
        try {
            //
            tbSecKill = this.getById(killId);
            if(tbSecKill == null) {
                return false;
            }

            //-- 把redis中的剩余商品取出来，删除key
            Object o = redisTemplate.opsForValue().get(key);
            if(o == null) {
                return true;
            }

            //-- 回归库存
            Integer count = (Integer) o;
            if(count <= 0) {
                return true;
            }

            // 获取产品产品剩余库存
            TbWare tbWare = tbWareMapper.selectOne(
                    new QueryWrapper<TbWare>().lambda().eq(TbWare::getProductId, tbSecKill.getProducId()).last("limit 1")
            );
            if(tbWare == null) {
                return false;
            }

            tbWare.setWareCount(tbWare.getWareCount()+count);
            tbWare.setUpdateTime(null);
            tbWareMapper.updateById(tbWare);
        } finally {
            redisTemplate.delete(key);
            tbSecKill.setKillState(2);
            tbSecKill.setUpdateTime(null);
            updateById(tbSecKill);
        }

        return true;
    }
}




